package com.excilys.capicsoubank.controllers;

import java.util.List;

import javax.validation.Valid;

import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.excilys.capicsoubank.entities.Account;
import com.excilys.capicsoubank.entities.TransactionType;
import com.excilys.capicsoubank.exception.NegativeBalanceException;
import com.excilys.capicsoubank.form.TransferForm;

/**
 * Contrôle l'affichage de la page de virements internes.
 * 
 * @author Tiphaine Ruy
 */
@Controller
@RequestMapping("/transfer")
public class TransferController extends PaginationController {

	private static final Logger LOGGER = LoggerFactory
			.getLogger(HomeController.class);

	/**
	 * Permet d'afficher le formulaire pour effectuer un virement. Mapping :
	 * /transfer
	 * 
	 * @param model
	 *            Le modèle
	 * @return La vue transfer.jsp
	 */
	@RequestMapping("")
	public String accountList(Model model) {

		List<Account> accounts = accountService.getAccountsConnectedUser();
		model.addAttribute("accounts", accounts);

		if (!model.containsAttribute("transferForm"))
			model.addAttribute("transferForm", new TransferForm());

		return Template.page("transfers", "transfer", model, null);
	}

	/**
	 * Récupère le formulaire rempli, valide ses informations et effectue le
	 * virement. Mapping (en POST) : /transfer
	 * 
	 * @param model
	 *            Le modèle
	 * @param redirectAttributes
	 *            Le modèle utilisé pour la redirection
	 * @param transferForm
	 *            Le formulaire rempli
	 * @param result
	 *            Le resultat de la validation
	 * @return Redirection vers /home
	 */
	@RequestMapping(value = "", method = RequestMethod.POST)
	public String transferPost(Model model,
			RedirectAttributes redirectAttributes,
			@Valid @ModelAttribute("transferForm") TransferForm transferForm,
			BindingResult result) {

		redirectAttributes.addFlashAttribute("transferForm", transferForm);

		if (result.hasErrors()) {
			redirectAttributes
					.addFlashAttribute(
							"org.springframework.validation.BindingResult.transferForm",
							result);
			return Template.error("FormValidationException", "/transfer",
					redirectAttributes);
		}

		try {
			long amount = TransferForm.getLongAmount(transferForm.getAmount());

			transactionService.transferBetweenAccounts(
					transferForm.getAccountSource(),
					transferForm.getAccountDestination(), amount);
		} catch (NegativeBalanceException e) {
			return Template.error(e, "/transfer", redirectAttributes);
		}

		return "redirect:/account/" + transferForm.getAccountSource();
	}

	/**
	 * Affiche la première page des virements du compte choisi pour le mois
	 * courant. Mapping : /transfer/accountId
	 * 
	 * @param accountId
	 *            L'id du compte choisi
	 * @return Redirige vers /transfer/accountId/currentYear/currentMonth
	 */
	@RequestMapping("/{accountId}")
	public String transferHistoryOnlyAccountId(
			@PathVariable("accountId") int accountId) {

		LOGGER.debug("/transfer/{}", accountId);

		DateTime now = DateTime.now();

		return "redirect:/transfer/" + accountId + "/" + now.year().get() + "/"
				+ now.monthOfYear().get();
	}

	/**
	 * Affiche la première page des virements du compte choisi pour l'année et
	 * le mois voulu. Mapping : /transfer/accountId/year/month
	 * 
	 * @param accountId
	 *            L'id du compte choisi
	 * @param year
	 *            L'année voulue
	 * @param month
	 *            Le mois voulu
	 * @return Redirige vers /transfer/accountId/year/month/1
	 */
	@RequestMapping("/{accountId}/{year}/{month}")
	public String transferHistoryWithoutPage(
			@PathVariable("accountId") int accountId,
			@PathVariable("year") int year, @PathVariable("month") int month) {

		Object[] params = { accountId, year, month };
		LOGGER.debug("/transfer/{}/{}/{}", params);

		return "redirect:/transfer/" + accountId + "/" + year + "/" + month
				+ "/1";
	}

	/**
	 * Affiche la page indiquée des virements du compte choisi pour l'année et
	 * le mois voulu. Mapping : /transfer/accountId/year/month/page
	 * 
	 * @param model
	 *            Le modèle
	 * @param redirectAttributes
	 *            Le modèle utilisé pour la redirection
	 * @param accountId
	 *            L'id du compte choisi
	 * @param year
	 *            L'année voulue
	 * @param month
	 *            Le mois voulu
	 * @param page
	 *            La page désirée
	 * @return La vue transferHistory.jsp
	 */
	@RequestMapping("/{accountId}/{year}/{month}/{page}")
	public String transferHistory(Model model,
			RedirectAttributes redirectAttributes,
			@PathVariable("accountId") int accountId,
			@PathVariable("year") int year, @PathVariable("month") int month,
			@PathVariable("page") int page) {

		Object[] params = { accountId, year, month, page };
		LOGGER.debug("/transfer/{}/{}/{}/{}", params);

		paginationController(model, accountId, year, month, page,
				TransactionType.TRANSFER);

		model.addAttribute("dateSelectedMonth", getFirstDayOfMonth(year, month));

		return Template.page("transfers", "transferHistory", model,
				Account.class.cast(model.asMap().get("account")).getLabel());
	}
}
